/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wap.rockvilletech.util.imaging;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import javax.imageio.ImageIO;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;

import org.apache.log4j.Logger;
/**
 *
 * @author Usman
 */
public class ProcessWallpaper {
	
    private static final Logger log=Logger.getLogger(ProcessWallpaper.class);
    
    /**
     * <pre>
     * Dynamically resize images.
     * bias: (0.9:0.5), this means (if extra image area is to be included then):
     *    0.9 = 9:1 ratio between Right & Left for the inclusion of x region
     *    0.5 = 1:1 ratio between Bottom & Top for the inclusion of y region
     * </pre>
     * @param imagePath Full Path of the Image be precessed
     * @param point1 Top Left Coordinates (X1:Y1) of the Area to be included
     * @param point2 Bottom Right Coordinates (X2:Y2) of the Area to be included
     * @param bias The proportion (xBias:yBias) in which to include the extra image portions(incase needed)
     * @param fillColor The background Fill Color
     * @param outputWidth The desired output width
     * @param outputHeight The desired output Height
     * @return Bufferedimage The generated image
     */
    public static BufferedImage generateWallpaper(String imagePath, String point1, String point2, String bias, String fillColor,
            String outputWidth, String outputHeight) {
        
        BufferedImage image = null;
        
        try {
            image = ImageIO.read( new File( imagePath ) );
        }
        catch(Exception e) {
            log.error("Exception in Read Image file =",e);
        }
            
        if( image == null ) {
            return null;
        }
        
        try {
            boolean toCrop = false;
            boolean toScale = false;
            
            // variables used to crop the image
            float topLeftX = 0;
            float topLeftY = 0;
            float cropWidth = 0;
            float cropHeight = 0;
            float xBias = (float)0.5;
            float yBias = (float)0.5;
            
            float mainAreaX1 = 0;
            float mainAreaX2 = 0;
            float mainAreaY1 = 500;
            float mainAreaY2 = 500;
            
            try { mainAreaX1 = Float.parseFloat( point1.substring(0, point1.indexOf(":")).trim() ); } catch(Exception e) {}
            try { mainAreaY1 = Float.parseFloat( point1.substring(point1.indexOf(":")+1).trim() ); } catch(Exception e) {}
            try { mainAreaX2 = Float.parseFloat( point2.substring(0, point2.indexOf(":")) ); } catch(Exception e) {}
            try { mainAreaY2 = Float.parseFloat( point2.substring(point2.indexOf(":")+1).trim() ); } catch(Exception e) {}
            
            try { xBias = Float.parseFloat( bias.substring(0, bias.indexOf(":")) ); } catch(Exception e) {}
            try { yBias = Float.parseFloat( bias.substring(bias.indexOf(":")+1).trim() ); } catch(Exception e) {}
            
            float mainAreaWidth = mainAreaX2 - mainAreaX1;
            float mainAreaHeight = mainAreaY2 - mainAreaY1;
            float mainAreaRatio = 0;
            
            int deviceWidth = Integer.parseInt( outputWidth );
            int deviceHeight = Integer.parseInt( outputHeight );
            float deviceRatio = (float)deviceWidth/(float)deviceHeight;
            
            int imageWidth = image.getWidth();
            int imageHeight = image.getHeight();
            
            if(imageHeight > deviceHeight || imageWidth > deviceWidth)
                toCrop = true;
            
            if(mainAreaWidth > deviceWidth || mainAreaHeight > deviceHeight)
                toScale = true;
            
            if( deviceWidth >= imageWidth ) {

            }
            else {
                float heightDiff = 0;
                float widthDiff = 0;
                
                topLeftX = mainAreaX1;
                topLeftY = mainAreaY1;
                cropHeight = mainAreaHeight;
                cropWidth = mainAreaWidth;
                
                if(deviceWidth > cropWidth) {
                    // Calculate new cropWidth and Adjust topLeftX accordingly
                    topLeftX = topLeftX - (deviceWidth - cropWidth)/2;
                    if(topLeftX < 0) topLeftX = 0;
                    cropWidth = deviceWidth;
                    mainAreaWidth = cropWidth;
                    
                }
                if(deviceHeight > cropHeight) {
                    // Calculate new cropHeight and Adjust topLeftY accordingly
                    topLeftY = topLeftY - (deviceHeight - cropHeight)/2;
                    if(topLeftY < 0) topLeftY = 0;
                    cropHeight = deviceHeight;
                    mainAreaHeight = cropHeight;
                }
                
                mainAreaRatio = (float)mainAreaWidth/(float)mainAreaHeight;
                
                if(mainAreaRatio == deviceRatio) {
                    
                }
                else if(mainAreaRatio > deviceRatio) {
                    
                    mainAreaHeight = mainAreaWidth / deviceRatio;
                    // if the calculated height is greater than the image height
                    // we will be using the whole height 
                    if(mainAreaHeight > imageHeight) {
                        cropHeight = mainAreaHeight;
                        topLeftY = 0;
                    }
                    else {
                        heightDiff = mainAreaHeight - (mainAreaY2 - mainAreaY1);
                        float increaseHeightToBottom = heightDiff * yBias;

                        mainAreaY1 = mainAreaY1 - (heightDiff - increaseHeightToBottom);

                        // if the increasedHeight is greater than the image hieght, 
                        // adjust the overflow height to the start initial Y value i.e. mainAreaY1
                        if(mainAreaY2 + increaseHeightToBottom > imageHeight) {
                            mainAreaY1 = mainAreaY1 - (mainAreaY2 + increaseHeightToBottom - imageHeight);
                            mainAreaY2 = imageHeight;
                        }
                        else {
                            mainAreaY2 = mainAreaY2 + increaseHeightToBottom;
                        }

                        topLeftY = mainAreaY1;

                        if(topLeftY < 0) { topLeftY = 0; }

                        cropHeight = mainAreaY2 - mainAreaY1;
                    }
                }
                else {
                    
                    mainAreaWidth = mainAreaHeight * deviceRatio;
                    if(mainAreaWidth > imageWidth) {
                        cropWidth = mainAreaWidth;
                        topLeftX = 0;
                    }
                    else {
                        widthDiff = mainAreaWidth - (mainAreaX2 - mainAreaX1);
                        float increaseWidthToRight = widthDiff * xBias;
                        
                        mainAreaX1 = mainAreaX1 - (widthDiff - increaseWidthToRight);
                        
                        if(mainAreaX2 + increaseWidthToRight > imageWidth) {
                            mainAreaX1 = mainAreaX1 - (mainAreaX2 + increaseWidthToRight - imageWidth);
                            mainAreaX2 = imageWidth;
                        }
                        else {
                            mainAreaX2 = mainAreaX2 + increaseWidthToRight;
                        }
                        
                        topLeftX = mainAreaX1;
                        
                        if(topLeftX < 0) { topLeftX = 0; }
                        
                        cropWidth = mainAreaX2 - mainAreaX1;
                    }
                }
                
                float tmpWidth = cropWidth, tmpHeight = cropHeight;
                int xOffSet = 0, yOffSet = 0;
                boolean createtmpImage = false;
                
                if(cropHeight > imageHeight) {
                    yOffSet = (int) ((cropHeight - imageHeight)/2);
                    //tmpHeight = cropHeight + 1; // 1 added to be on the safer side
                    tmpHeight = cropHeight;
                    cropHeight = imageHeight;
                    createtmpImage = true;
                }
                if(cropWidth > imageWidth) {
                    xOffSet = (int) ((cropWidth - imageWidth)/2);
                    //tmpWidth = cropWidth + 1; // 1 added to be on the safer side
                    tmpWidth = cropWidth;
                    cropWidth = imageWidth;
                    createtmpImage = true;
                }
                
                 log.info("\n");
                 log.info(" ORIGINAL ----->\n imageWidth: "+imageWidth+"\n imageHeight: "+imageHeight);
                
                if(toCrop) {
                    ParameterBlock pb = new ParameterBlock();
                    pb.addSource( image ); // The source image

                    pb.add( topLeftX ); // The xScale
                    pb.add( topLeftY ); // The yScale
                    pb.add( (float)(Math.floor((double)cropWidth)) ); // The x translation
                    pb.add( (float)(Math.floor((double)cropHeight)) ); // The y translation
                    pb.add( Interpolation.getInstance(Interpolation.INTERP_BILINEAR) );
                    
                    log.info(" CROP ----->\n topLeftX: "+topLeftX+"\n topLeftY: "+topLeftY+"\n cropWidth: "+Math.floor((double)cropWidth)+"\n cropHeight: "+Math.floor((double)cropHeight));
                    try {
                        image = JAI.create( "crop", pb ).getAsBufferedImage();
                    }
                    catch(Exception e) {
                        log.error("Exception During Croping phase :",e);
                    }
                    
                }
                
                if(createtmpImage) {
                    BufferedImage tmpImage = new BufferedImage( (int)tmpWidth, (int)tmpHeight, BufferedImage.TYPE_INT_RGB );

                    Graphics gti = tmpImage.getGraphics();
                    // set the default fill Colot to Black
                    Color myColor = new Color(0, 0, 0);
                    // try to parse the user provided Color code
                    try {
                        if(fillColor.length() > 0) {
                            // If any color is passed, try to decode it
                            if(fillColor.startsWith("#")) myColor = Color.decode(fillColor);
                            else myColor = Color.decode("#"+fillColor);
                        }
                        else { 
                            myColor = null;
                        }
                    } catch(Exception e) {
                        log.error("Exception In Fill Color : ",e);
                        myColor = null; }
                    if(myColor == null ) myColor = Color.BLACK;
                    // Fill the whole image with the desired Color.
                    gti.setColor(myColor);
                    gti.fillRect(0,0,tmpImage.getWidth(),tmpImage.getHeight());
                    
                    //gti.drawImage(image.getScaledInstance(image.getWidth(), image.getHeight(), image.SCALE_DEFAULT), xOffSet, yOffSet, null);
                    gti.drawImage(image, xOffSet, yOffSet, null);
                    
                    image = tmpImage;
                    
                    gti.dispose();
                    gti.finalize();
                    
                    tmpImage.flush();
                    tmpImage = null;
                }
                
                float xscale = (float)deviceWidth / mainAreaWidth;
                float yscale = (float)deviceHeight / mainAreaHeight;
                
                if(toScale) {
                    ParameterBlock pb = new ParameterBlock();
                    pb.addSource( image ); // The source image

                    pb.add( xscale ); // The xScale
                    pb.add( xscale ); // The yScale
                    pb.add( 0.0F ); // The x translation
                    pb.add( 0.0F ); // The y translation
                    pb.add( Interpolation.getInstance(Interpolation.INTERP_BILINEAR) );
                    
                    log.info(" SCALE ----->\n xscale: "+xscale);
                    image = JAI.create( "scale", pb ).getAsBufferedImage();
                    
                }
            }
        }
        catch(Exception e) {
        log.error("Exception in ProcessWallpaper : ",e);
        }
        
        return image;
    }
}
